package wiki.xsx.core.jmeter.core.assertion;

import wiki.xsx.core.jmeter.core.enums.JmeterAssertionMatchMode;
import wiki.xsx.core.jmeter.core.enums.JmeterAssertionTestField;
import wiki.xsx.core.jmeter.core.enums.JmeterScope;
import wiki.xsx.core.jmeter.core.util.JmeterOptional;
import wiki.xsx.core.jmeter.core.util.JmeterScopeUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.jmeter.assertions.Assertion;
import org.apache.jmeter.assertions.ResponseAssertion;
import org.apache.jmeter.assertions.gui.AssertionGui;
import org.apache.jmeter.testelement.TestElement;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 默认响应断言
 *
 * @author xsx
 * @date 2022/8/29
 * @since 1.8
 * <p>
 * Copyright (c) 2022 xsx All Rights Reserved.
 * easy-jmeter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
@Data
@Accessors(chain = true)
public class JmeterDefaultResponseAssertion implements JmeterAssertion {

    /**
     * 测试类名称
     */
    public static final String TEST_CLASS_NAME = ResponseAssertion.class.getName();
    /**
     * GUI类名称
     */
    public static final String GUI_CLASS_NAME = AssertionGui.class.getName();

    /**
     * 断言名称
     */
    private String name;
    /**
     * 断言注释
     */
    private String comment;
    /**
     * 范围变量名称（自定义变量）
     */
    private String scopeVariableName;
    /**
     * 断言范围
     */
    private JmeterScope scope;
    /**
     * 测试字段
     */
    private JmeterAssertionTestField testField;
    /**
     * 匹配模式
     */
    private JmeterAssertionMatchMode matchMode;
    /**
     * 匹配内容
     */
    private List<String> matchContents;
    /**
     * 失败消息
     */
    private String failureMessage;
    /**
     * 是否忽略状态
     */
    private Boolean isAssumeSuccess;
    /**
     * 是否取反（匹配模式）
     */
    private Boolean isMatchNot;
    /**
     * 是否为或（匹配模式）
     */
    private Boolean isMatchOr;

    /**
     * 无参构造
     */
    private JmeterDefaultResponseAssertion() {
    }

    /**
     * 获取响应断言实例
     *
     * @return 返回响应断言实例
     */
    public static JmeterDefaultResponseAssertion getInstance() {
        return new JmeterDefaultResponseAssertion();
    }

    /**
     * 初始化匹配内容容量
     *
     * @param initialCapacity 初始容量
     * @return 返回响应断言
     */
    public JmeterDefaultResponseAssertion initialMatchContentCapacity(int initialCapacity) {
        this.matchContents = new ArrayList<>(initialCapacity);
        return this;
    }

    /**
     * 添加匹配内容
     *
     * @param matchContents 匹配内容
     * @return 返回响应断言
     */
    public JmeterDefaultResponseAssertion addMatchContent(String... matchContents) {
        // 如果匹配内容为空，则初始化匹配内容
        if (this.matchContents == null) {
            // 初始化匹配内容
            this.matchContents = new ArrayList<>(10);
        }
        // 添加匹配内容
        Collections.addAll(this.matchContents, matchContents);
        // 返回断言
        return this;
    }

    /**
     * 创建断言
     *
     * @return 返回断言
     */
    @Override
    public Assertion create() {
        // 创建响应断言
        ResponseAssertion responseAssertion = new ResponseAssertion();
        // 设置测试类名称
        responseAssertion.setProperty(TestElement.TEST_CLASS, TEST_CLASS_NAME);
        // 设置GUI类名称
        responseAssertion.setProperty(TestElement.GUI_CLASS, GUI_CLASS_NAME);
        // 设置启用
        responseAssertion.setEnabled(true);
        // 设置断言名称
        responseAssertion.setName(JmeterOptional.ofNullable(this.name).orElse("响应断言"));
        // 设置断言注释
        responseAssertion.setComment(JmeterOptional.ofNullable(this.comment).orElse(""));
        // 设置是否忽略状态
        responseAssertion.setAssumeSuccess(JmeterOptional.ofNullable(this.isAssumeSuccess).orElse(Boolean.FALSE));
        // 设置范围
        JmeterOptional.ofNullable(this.scope).orElse(JmeterOptional.of(JmeterScope.ONLY_MAIN_SAMPLE)).ifPresent(scope -> JmeterScopeUtil.initScope(scope, this.scopeVariableName, responseAssertion));
        // 设置测试字段
        JmeterOptional.ofNullable(this.testField).ifPresent(testField -> this.initTestField(testField, responseAssertion));
        // 设置匹配模式
        JmeterOptional.ofNullable(this.matchMode).ifPresent(matchMode -> this.initMatchMode(matchMode, responseAssertion));
        // 设置是否取反
        JmeterOptional.ofNullable(this.isMatchNot).ifTrue(v -> responseAssertion.setToNotType());
        // 设置是否为或
        JmeterOptional.ofNullable(this.isMatchOr).ifPresent(v -> responseAssertion.setToOrType());
        // 设置匹配内容
        JmeterOptional.ofNullable(this.matchContents).ifPresent(v -> v.stream().filter(Objects::nonNull).forEach(responseAssertion::addTestString));
        // 设置失败消息
        JmeterOptional.ofNullable(this.failureMessage).ifPresent(responseAssertion::setCustomFailureMessage);
        // 返回响应断言
        return responseAssertion;
    }
}
